
class HTTPHeaders(dict):
    """A dictionary that maintains Http-Header-Case for all keys."""
    def __setitem__(self, name, value):
        dict.__setitem__(self, self._normalize_name(name), value)

    def __getitem__(self, name):
        return dict.__getitem__(self, self._normalize_name(name))

    def _normalize_name(self, name):
        return "-".join([w.capitalize() for w in name.split("-")])

    @classmethod
    def parse(cls, headers_bytes):
        headers = cls()
        header_string = headers_bytes.decode('utf-8')
        for line in header_string.splitlines():
            if line:
                name, value = line.split(":", 1)
                headers[name] = value.strip()
        return headers

from io import BytesIO

def parse_multipart(body, boundary):
    files = {}
    arguments = {}

    boundary = boundary.encode('latin-1')
    if boundary.startswith(b'"') and boundary.endswith(b'"'):
        boundary = boundary[1:-1]
    if body.endswith(b"\r\n"):
        footer_length = len(boundary) + 6
    else:
        footer_length = len(boundary) + 4
    parts = body[:-footer_length].split(b"--" + boundary + b"\r\n")
    for part in parts:
        if not part: continue
        eoh = part.find(b"\r\n\r\n")
        if eoh == -1:
            logging.warning("multipart/form-data missing headers")
            continue
        headers = HTTPHeaders.parse(part[:eoh])
        name_header = headers.get("Content-Disposition", "")
        if not name_header.startswith("form-data;") or \
           not part.endswith(b"\r\n"):
            logging.warning("Invalid multipart/form-data")
            continue
        value = part[eoh + 4:-2]
        name_values = {}
        for name_part in name_header[10:].split(";"):
            name, name_value = name_part.strip().split("=", 1)
            name_values[name] = name_value.strip('"')
        if not name_values.get("name"):
            logging.warning("multipart/form-data value missing name")
            continue
        name = name_values["name"]
        if name_values.get("filename"):
            ctype = headers.get("Content-Type", "application/unknown")
            files.setdefault(name, []).append({
                'filename': name_values["filename"], 
                'input': BytesIO(value),
                'content_type': ctype,
                'length': len(value)
            })
        else:
            arguments.setdefault(name, []).append(value.decode('utf-8'))
    return arguments, files

